//
//  sbuxscrapeAppDelegate.m
//  sbuxscrape
//
//  Created by Scot Shinderman on 7/26/08.
// Copyright 2008 Elliptic. All rights reserved.
//

#import "sbuxscrapeViewController.h"
#import "libxml/HTMLparser.h"
#import "libxml/tree.h"




@interface LoginParse : NSObject
{
	NSMutableDictionary  *inputFields_;
	bool parsingForm_;
	NSString *formURL_;
}
@property (readonly) NSDictionary* inputFields_;
@property (readonly) NSString* formURL_;

-(void) parseTree:(xmlNodePtr) cur;

@end

@implementation LoginParse
@synthesize inputFields_;
@synthesize formURL_;


- (id) init
{
	self = [super init];
	if (self != nil) {
		parsingForm_ = FALSE;
		formURL_ = nil;
		inputFields_ = [[NSMutableDictionary dictionaryWithCapacity:50] retain];
	}
	return self;
}


/*
 currentNode: form
   prop: name
     currentNode: text, content: MEMBERLOGIN
   prop: action
     currentNode:text, content:URL
 
  currentNode: input, content:(null)
    prop: type
      currentNode: text, content:hidden
    prop: name
      currentNode: text, content:ts
    prop: value
      currentNode: text, content:1219765312
*/


static xmlAttrPtr findprop( xmlNodePtr node, const char  *str )
{
	for( xmlAttrPtr prop=node->properties;  prop;  prop=prop->next )
	{
		if( !prop->name ) continue;
		
		if( !strcmp( (const char*) prop->name, str ) )
			return prop;
	}
	
	return 0;
}

static xmlNodePtr findNode( xmlNodePtr node, const char *name, const char *content )
{
	for( ;	node;  node=node->next )
	{
		if( !node->name ) continue;
		if( !node->content ) continue;
		
		if( !strcmp( (const char*) node->name, name ) && !strcmp( (const char *) node->content, content ) )
			return node;
	}
	
	return 0;
}


static const char * findNodeContents( xmlNodePtr node, const char *name )
{
	for( ;	node;  node=node->next )
	{
		if( !node->name ) continue;
		
		if( !strcmp( (const char *) node->name, name ) )
			return (const char *) node->content;
	}
	
	return 0;
}


// note -- pass in the xml node, this will descend via  children pointer
-(void) parseFormInputs:(xmlNodePtr)cur
{	
	for( cur=cur->xmlChildrenNode;	cur;  cur=cur->next )
	{
		if( cur->name && !strcmp( (const char*) cur->name, "input" ) )
		{
			xmlAttrPtr nameprop   = findprop( cur, "name" );
			xmlAttrPtr typeprop   = findprop( cur, "type" );
			xmlAttrPtr valueprop   = findprop( cur, "value" );
			if( nameprop && typeprop && valueprop )
			{
				const char *name_contents = findNodeContents( nameprop->children, "text" );
				//const char *type_contents = findNodeContents( typeprop->children, "text" );
				const char *val_contents = findNodeContents( valueprop->children, "text" );
				
				//printf( "input name(%s) type(%s) val(%s)\n", name_contents, type_contents, val_contents );
				
				if( val_contents && name_contents )
				{						
					[inputFields_ setObject:[NSString stringWithCString:val_contents] 
									 forKey:[NSString stringWithCString:name_contents]];
				}
			}
		}
		else if( !strcmp( (const char*) cur->name, "select" ) )
		{
		}			
		
		// recurse.
		[self parseFormInputs: cur];
	}	 	
}


-(void) parseTree:(xmlNodePtr)cur
{
	if( !cur )
		return;

	
	if( cur->name && !strcmp( (const char*) cur->name, "form" ) )
	{
		xmlAttrPtr nameprop   = findprop( cur, "name" );
		xmlAttrPtr actionprop = findprop( cur, "action" );
		if( nameprop && actionprop && findNode( nameprop->children, "text", "MEMBERLOGIN" ) )	
		{
			const char *url = findNodeContents( actionprop->children, "text" );
			if( url )
			{
				parsingForm_ = TRUE;
				formURL_ = [NSString stringWithCString:url];
				[self parseFormInputs:cur];
				parsingForm_ = FALSE;
			}
		}
	}
	
	// continue search
	for( cur=cur->xmlChildrenNode;	cur;  cur=cur->next )
	{
		[self parseTree:cur];
	}	
	
}		
					
/*	
	//for( i=0; i<depth; ++i )  printf( "  " );	
	//printf( "currentNode: %s, content:%s\n", cur->name, cur->content );

 xmlAttrPtr properties = cur->properties;
	while( properties )
	{
		for( i=0; i<depth+1; ++i )  printf( "  " );	
		printf( "prop: %s\n", properties->name );
		printTree( properties->children, depth+2 );
		
		properties = properties->next;
	}
		
	cur = cur->xmlChildrenNode;	
	while (cur) 
	{
		printTree( cur, 1+depth );			
		cur = cur->next;
	}
 */


@end




@implementation sbuxscrapeViewController

@synthesize url_, username_, password_;
@synthesize text_;
@synthesize dbgview_, dbgswitch_, scrollview_;

/*
 Implement loadView if you want to create a view hierarchy programmatically
- (void)loadView {
}
 */


-(IBAction)toggleswitch
{
	if( dbgview_.superview == nil )
	{
		[scrollview_ addSubview:dbgview_];
	}
	else
	{
		[dbgview_ removeFromSuperview];		
	}
}


- (void)viewDidLoad {
	[super viewDidLoad];		
	[self.view setBackgroundColor:[UIColor groupTableViewBackgroundColor]];

	url_.clearButtonMode = UITextFieldViewModeWhileEditing;
	//url_.text = @"http://";

							  
	[text_ setFont:[UIFont systemFontOfSize:10.0]];
	[text_ setBackgroundColor:[UIColor whiteColor]];
	text_.scrollEnabled = TRUE;
	text_.scrollsToTop = TRUE;
	text_.showsVerticalScrollIndicator = TRUE;

	dbgview_.alpha = 0.3;
	[dbgview_ removeFromSuperview];
	
	username_.text = [[NSUserDefaults standardUserDefaults] stringForKey:@"username"];
	password_.text = [[NSUserDefaults standardUserDefaults] stringForKey:@"password"];		
}



// When the user presses return, take focus away from the text field so that the keyboard is dismissed.
- (BOOL)textFieldShouldReturn:(UITextField *)theTextField {
	[theTextField resignFirstResponder];
	return YES;
}



- (void)textFieldDidEndEditing:(UITextField *)textField
{
	//printf( "text field did end editing\n" );
}


- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
	// Return YES for supported orientations
	return (interfaceOrientation == UIInterfaceOrientationPortrait);
}


- (void)didReceiveMemoryWarning {
	[super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
	// Release anything that's not essential, such as cached data
}


- (void)dealloc {
	[super dealloc];
}



// -----------------------------------------------------------------------------------------------
// form post.
// -----------------------------------------------------------------------------------------------
-(void)postForm:(NSString*)aURL body:(NSString*)body
{	
    NSString *URL = (NSString*)CFURLCreateStringByAddingPercentEscapes(NULL, (CFStringRef)aURL, (CFStringRef)@"%", NULL, kCFStringEncodingUTF8);
    [URL autorelease];
	NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:URL]
                                                       cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
                                                   timeoutInterval:60.0];
    
    
    [req setHTTPMethod:@"POST"];
    [req setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
    
    int contentLength = [body lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
    
    [req setValue:[NSString stringWithFormat:@"%d", contentLength] forHTTPHeaderField:@"Content-Length"];
    [req setHTTPBody:[NSData dataWithBytes:[body UTF8String] length:contentLength]];
    
	
    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
	NSURLResponse * response;
	NSError * error = NULL;
	NSData *data = [NSURLConnection sendSynchronousRequest:req  returningResponse:&response error:&error];
	if( error ) {
		printf( "Error: %s\n", [[error localizedDescription] UTF8String] );
		[[[UIAlertView alloc] initWithTitle:@"error" message:[error localizedDescription] delegate:self cancelButtonTitle:@"ok" 
						  otherButtonTitles:NULL] show];
	}
	
    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
	
	text_.text = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}


// -----------------------------------------------------------------------------------------------
// mime (multi part) post.
// -----------------------------------------------------------------------------------------------
-(void)post:(NSString*)aURL body:(NSString*)databody   sourcewebaddress:(NSString*)sourcewebaddress
{
    NSString *URL = (NSString*)CFURLCreateStringByAddingPercentEscapes(NULL, (CFStringRef)aURL, (CFStringRef)@"%", NULL, kCFStringEncodingUTF8);
    [URL autorelease];

	NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:URL]
                                                       cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
                                                   timeoutInterval:60.0];    
    [req setHTTPMethod:@"POST"];


	NSString *stringBoundary = @"0xKhTmLbOuNdArY";
	NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",stringBoundary];
	[req addValue:contentType forHTTPHeaderField: @"Content-Type"];


	NSMutableData *postBody = [NSMutableData data];
	[postBody appendData:[[NSString stringWithFormat:@"--%@\r\n",stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];

	// piece
	[postBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n",@"source"] 
									dataUsingEncoding:NSUTF8StringEncoding]];
	[postBody appendData:[sourcewebaddress dataUsingEncoding:NSUTF8StringEncoding]];
	[postBody appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];

	
	//piece
	[postBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n",@"content"] 
									dataUsingEncoding:NSUTF8StringEncoding]];
	[postBody appendData:[@"Content-Type: Text/plain\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
	[postBody appendData:[databody dataUsingEncoding:NSUTF8StringEncoding]];
	[postBody appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];
	
	// finished
	[postBody appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n",stringBoundary] dataUsingEncoding:NSUTF8StringEncoding]];

	[req setHTTPBody:postBody];

	
	//NSString *s2 = [[NSString alloc] initWithBytes:[postBody bytes] length:[postBody length] encoding:NSUTF8StringEncoding];
	//printf( "%s", [s2 UTF8String] );
	
	
    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
	NSURLResponse * response;
	NSError * error = NULL;
	[NSURLConnection sendSynchronousRequest:req  returningResponse:&response error:&error];
	if( error ) {
		printf( "Error: %s\n", [[error localizedDescription] UTF8String] );
		[[[UIAlertView alloc] initWithTitle:@"error" message:[error localizedDescription] delegate:self cancelButtonTitle:@"ok" 
						  otherButtonTitles:NULL] show];
	}
	
    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}


// -----------------------------------------------------------------------------------------------
// print xml tree
// -----------------------------------------------------------------------------------------------
static void printTree( xmlNodePtr cur, int depth )
{
	if( !cur )
		return;

	int i;
	for( i=0; i<depth; ++i )  printf( "  " );	
	printf( "currentNode: %s, content:%s\n", cur->name, cur->content );
	
	xmlAttrPtr properties = cur->properties;
	while( properties )
	{
		for( i=0; i<depth+1; ++i )  printf( "  " );	
		printf( "prop: %s\n", properties->name );
		printTree( properties->children, depth+2 );
		
		properties = properties->next;
	}
	
	
	cur = cur->xmlChildrenNode;	
	while (cur) 
	{
		printTree( cur, 1+depth );			
		cur = cur->next;
	}
}



- (void) parseString:(NSString*)s
{	
	unsigned char *doc = (unsigned char *)strdup( [s UTF8String] );
	htmlDocPtr htmlptr = htmlParseDoc( doc, NULL );
	if( htmlptr )
	{
		xmlNodePtr cur = xmlDocGetRootElement(htmlptr);
		printTree(cur,0);
		xmlFreeDoc( htmlptr );
	}
	
	free(doc);
}


-(bool)checkId
{
	// how do get rid of keyboard?
	[url_ resignFirstResponder];
	[password_ resignFirstResponder];
    [username_ resignFirstResponder];
	
	NSString *username = username_.text;
	NSString *password = password_.text;
	
	if( ![username length] || ![password length] )
	{
		[[[UIAlertView alloc] initWithTitle:@"Error" message:@"missing username/password" delegate:self cancelButtonTitle:@"ok" 
						  otherButtonTitles:NULL] show];	
		return FALSE;
	}
	
	[[NSUserDefaults standardUserDefaults] setObject:username forKey:@"username"];
	[[NSUserDefaults standardUserDefaults] setObject:password forKey:@"password"];
	return TRUE;
}


-(void) autologin:(NSString*) s1
{
	if( !s1 || ![s1 UTF8String] ) {
		return;
	}
	
	unsigned char *doc = (unsigned char *)strdup( [s1 UTF8String] );	
	if( !doc ) {
		text_.text = @"error duplicating string";
		return;
	}
	
	htmlDocPtr htmlptr = htmlParseDoc( doc, NULL );
	if( !htmlptr ) {
		text_.text = @"htmlParseDoc failed";
		return;
	}
	
	xmlNodePtr root = xmlDocGetRootElement(htmlptr);			
	LoginParse *lp = [[LoginParse alloc] init];
	[lp parseTree:root];
	free(doc);
	
	NSDictionary *dictionary = lp.inputFields_;
	if(!dictionary) {
		text_.text = @"problem creating dictionary";
		return;
	}
	
	// hardcoded --
	// the dropdown chooser.
	[dictionary setValue:@"attwifi.com" forKey:@"roamRealm"];
	// the id
	// get from the text field		
	NSString *username = username_.text;
	NSString *password = password_.text;
	if( ![username length] || ![password length] )
	{
		return;
	}
	
	[dictionary setValue:username forKey:@"username"];
	[dictionary setValue:password forKey:@"password"];
		
	if( !lp.formURL_ ) {
		text_.text = @"couldn't find url for the form";
		return;
	}
	
	
	//
	// build the post command from the form input dictionary
	//
	bool first = TRUE;
	NSMutableString *body = [[NSMutableString stringWithCapacity:1000] retain]; 
	for (id key in dictionary)
	{
		NSString *v = [dictionary objectForKey:key];
		
		if(!first) {
			[body appendString:@"&"];			
		}
		
		[body appendString:key];
		[body appendString:@"="];
		[body appendString:v];
		
		first = FALSE;
	}

	NSString *enc = [[body stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding] retain];
	//printf( "sending ---> %s\n", [enc UTF8String] );
	url_.text = lp.formURL_;
	text_.text = enc;
	[self postForm:lp.formURL_ body:enc];	
}


// -----------------------------------------------------------------------------------------------
// debugging -- trial w/ canned html
// -----------------------------------------------------------------------------------------------
-(IBAction) test1
{
	// Get the main bundle for the app.
	NSBundle* mainBundle = [NSBundle mainBundle];	
	NSString *path = [mainBundle pathForResource:@"testing.html" ofType:nil];	
	NSString *s1 = [[NSString alloc] initWithContentsOfFile:path];
	printf( "file string length: %d\n", [s1 length] );

	[self autologin:s1];	
}


// -----------------------------------------------------------------------------------------------
// debugging
// -----------------------------------------------------------------------------------------------
-(IBAction) test2
{
	if( ![self checkId] )
		return;

	NSString *addr = url_.text;
	printf( "url:%s\n", [addr UTF8String]);
	if( !addr ) {
		text_.text = @"no address";
		return;
	}		
	
	
	NSURL *nsurl = [NSURL URLWithString:addr];
	NSError *error = NULL;
	NSString *s = [[NSString alloc] initWithContentsOfURL:nsurl encoding:NSASCIIStringEncoding error:&error];
	if( error ) {
		text_.text = [error localizedDescription];
		return;
	}
				
	[self autologin:s];	
}

// -----------------------------------------------------------------------------------------------
// attempt to download a real site, parse at&t login screen, autologin
// -----------------------------------------------------------------------------------------------
-(IBAction) test3
{
	if( ![self checkId] )
		return;
		
	NSURL *nsurl = [NSURL URLWithString:@"http://news.com"];
	NSError *error = NULL;	
	NSString *s = [[NSString alloc] initWithContentsOfURL:nsurl encoding:NSASCIIStringEncoding error:&error];
	text_.text = s;

	[self autologin:s];
}


// -----------------------------------------------------------------------------------------------
// get initial login screen, save to data location for next step
// -----------------------------------------------------------------------------------------------
- (IBAction)urlchanged:(id)sender
{	
	[url_ resignFirstResponder];
	
	NSString *addr = url_.text;
	printf( "url:%s\n", [addr UTF8String]);	
	NSURL *nsurl = [NSURL URLWithString:addr];
	NSError *error = NULL;
	
	//NSURLResponse *response;
	//NSData *d = [[NSURLConnection sendSynchronousRequest:[NSURLRequest requestWithURL:url] 
	//               returningResponse:&response error:&error] autorelease];
			
	NSString *s = [[NSString alloc] initWithContentsOfURL:nsurl encoding:NSASCIIStringEncoding error:&error];
	if( error )
	{
		printf( "Error: %s\n", [[error localizedDescription] UTF8String] );
	}
	else if( 1 )
	  {
		  // too soon
		//[self post:@"http://air-pix.appspot.com/sign" body:s sourcewebaddress:addr];
		//[self post:@"http://localhost:8080/sign" body:s sourcewebaddress:addr];

		  text_.text = s;
		  [text_ flashScrollIndicators];
		  [text_ setNeedsDisplay];
		  
		  // save to a file
		  //NSError error;
		  //[s writeToFile:"test.txt" atomically:NO encoding:NSUTF8StringEncoding error:&error];
		  [self writeApplicationData:[s dataUsingEncoding:NSUTF8StringEncoding]  toFile:@"test.txt"];
	  }
}

// -----------------------------------------------------------------------------------------------
// retrieve login screen data
// send to google app (must have real connection at this point)
// -----------------------------------------------------------------------------------------------
- (IBAction)mailit:(id)sender
{
	NSString *s = text_.text;
	if( ![text_ hasText] || [s length]<50 ) {

		NSData *d = [self applicationDataFromFile:@"test.txt"];
		NSString *s1 = [[NSString alloc] initWithData:d encoding:NSUTF8StringEncoding];		
		text_.text = s1;
	    return;
	}
	
	// write to real website
	[self post:@"http://air-pix.appspot.com/sign" body:s sourcewebaddress:@"test.txt"];	
	
	// write to local host -- testing w/ local google server.
	//[self post:@"http://localhost:8080/sign" body:s sourcewebaddress:@"test.txt"];
	text_.text = @"sent...";
	
	[[[UIAlertView alloc] initWithTitle:@"scrape" message:@"sent off to air-pix.appspot.com" delegate:self cancelButtonTitle:@"ok" 
					  otherButtonTitles:NULL] show];
	
}

// -----------------------------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------------------------
- (BOOL)writeApplicationData:(NSData *)data toFile:(NSString *)fileName {
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    if (!documentsDirectory) {
        NSLog(@"Documents directory not found!");
        return NO;
    }
    NSString *appFile = [documentsDirectory stringByAppendingPathComponent:fileName];
    return ([data writeToFile:appFile atomically:YES]);
}

// -----------------------------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------------------------
- (NSData *)applicationDataFromFile:(NSString *)fileName {
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *appFile = [documentsDirectory stringByAppendingPathComponent:fileName];
    NSData *myData = [[[NSData alloc] initWithContentsOfFile:appFile] autorelease];
    return myData;
}


// -----------------------------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------------------------
-(IBAction) sendmail:(id)sender
{
	NSString *str = @"mailto:AirPix.Support@gmail.com?subject=AirPix Comment&body=Hello";
	NSString *encoded = [str stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];	
	[[UIApplication sharedApplication] openURL:[NSURL URLWithString:encoded]];	
}


@end
